/*
 * TAuthenticator.cpp
 *
 *  Created on: 2012-10-30
 *      Author: minhua
 */

#include "TAuthenticator.h"
#include "TNetworkAccessManager.h"
#include <QUrl>
#include <QNetworkRequest>
#include "../TConfig.h"
#include "../TContext.h"
#include "../utils/TConverter.h"
#include <QNetworkProxy>
#include <QtNetwork>
#include "../requester/TXMLSerializer.h"
#include <QMessageBox>

TAuthenticator::TAuthenticator(QObject *parent) : QObject(parent)
{
}

TAuthenticator::TAuthenticator(QString loginName, QString password, QObject *parent) : QObject(parent)
{
	_loginName = loginName;
	_password = password;
}

TAuthenticator::TAuthenticator(QString loginName, QString oldPassword, QString newPassword, QObject *parent)
	 : QObject(parent)
{
	_loginName = loginName;
	_password = newPassword;
	_oldPassword = oldPassword;
}

TAuthenticator::~TAuthenticator()
{
	// TODO Auto-generated destructor stub
}

void TAuthenticator::innerLogin(QNetworkAccessManager *manager)
{
	disconnect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(done(QNetworkReply *)));
	disconnect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
			this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));

	connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(done(QNetworkReply *)));
	connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
			this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
	QUrl url(TContext::instance()->config()->serverUrl()+"login.action");
	QNetworkRequest request;
	request.setUrl(url);

	QHash<QString, QVariant> variables;
	variables.insert("version", TContext::instance()->config()->version());
	variables.insert("loginName", _loginName);
	variables.insert("loginPassword", _password);

	QByteArray content;
	QHashIterator<QString, QVariant> iterator(variables);
	while(iterator.hasNext())
	{
		if(iterator.hasPrevious())
		{
			content.append("&");
		}
		QString key = iterator.next().key();
		content.append(key);
		content.append("=");

		QVariant value = variables.value(key);
		switch(value.type())
		{
		case QVariant::Int:
			content.append(QString::number(value.toInt()));
			break;
		case QVariant::Double:
			content.append(QString::number(value.toDouble()));
			break;
		case QVariant::String:
			content.append(value.toString());
			break;
		case QVariant::Date:
			content.append(TConverter::dateToString(value.toDate()));
			break;
		case QVariant::Time:
			content.append(TConverter::timeToString(value.toTime()));
			break;
		case QVariant::DateTime:
			content.append(TConverter::datetimeToString(value.toDateTime()));
			break;
		default:
			break;
		}
	}
	TContext::instance()->logger()->debug("Login Content: " + content);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
	request.setHeader(QNetworkRequest::ContentLengthHeader, content.length());
	manager->post(request, content);

	manager->setProperty("connectCount" , manager->property("connectCount").toInt() + 1);


}

void TAuthenticator::login()
{
	QNetworkAccessManager *manager = new QNetworkAccessManager(this);
	QTime timeTmp;
	timeTmp.start();
	manager->setProperty("timeLoginCounter", timeTmp);
	_timeCounter.start();
	innerLogin(manager);
}

void TAuthenticator::modifyPassword()
{
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);

    connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(modifyDone(QNetworkReply *)));
    connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
            this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
    QUrl url(TContext::instance()->config()->serverUrl()+"login.action");
    QNetworkRequest request;
    request.setUrl(url);

	QHash<QString, QVariant> variables;
	variables.insert("username", _loginName);
	variables.insert("oldPassword", _oldPassword);
	variables.insert("newPassword", _password);

	QByteArray content;
	QHashIterator<QString, QVariant> iterator(variables);
	while(iterator.hasNext())
	{
		if(iterator.hasPrevious())
		{
			content.append("&");
		}
		QString key = iterator.next().key();
		content.append(key);
		content.append("=");

		QVariant value = variables.value(key);
		switch(value.type())
		{
		case QVariant::Int:
			content.append(QString::number(value.toInt()));
			break;
		case QVariant::Double:
			content.append(QString::number(value.toDouble()));
			break;
		case QVariant::String:
			content.append(value.toString());
			break;
		case QVariant::Date:
			content.append(TConverter::dateToString(value.toDate()));
			break;
		case QVariant::Time:
			content.append(TConverter::timeToString(value.toTime()));
			break;
		case QVariant::DateTime:
			content.append(TConverter::datetimeToString(value.toDateTime()));
			break;
		default:
			break;
		}
	}
	TContext::instance()->logger()->debug("Content: " + content);
	request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
	request.setHeader(QNetworkRequest::ContentLengthHeader, content.length());
	manager->post(request, content);
}

void TAuthenticator::sslErrors(QNetworkReply* reply,const QList<QSslError> &errors)
{
    QString errorString;
    foreach (const QSslError &error, errors)
    {
        QSslError::SslError sslerror  = error.error();
        if (sslerror == QSslError::NoError)
            continue;
        if (!errorString.isEmpty())
            errorString += ", ";
        errorString += error.errorString();
    }

    if (errorString != "")
    {
        TContext::instance()->logger()->error(tr("One or more SSL errors has occurred: %1").arg(errorString));
    }
    else
    {
    }
    reply->ignoreSslErrors();
}

void TAuthenticator::done(QNetworkReply *reply)
{
	TContext::instance()->logger()->debug("Login come back");
	QDomElement response;
	if(reply->error()==QNetworkReply::NoError)
	{
		QByteArray responseBody = reply->readAll();
		QString errorMessage;
		int errorLine;
		int errorColumn;
		QDomDocument doc;
		if(!doc.setContent(responseBody, &errorMessage, &errorLine, &errorColumn))
		{
			TContext::instance()->logger()->error("Parse the requester response failed: " + responseBody);
			emit loginFinished(true, TSessionPointer(NULL));
		}
		else
		{
			response = doc.documentElement();
			QDomElement errorElement = response.firstChildElement("error");
			if(!errorElement.isNull())
			{
				TContext::instance()->logger()->error("Backbone request error: " + errorElement.attribute("code"));
				emit loginFinished(true, TSessionPointer(NULL));
			}
			else
			{
				TSession *session = new TSession();

				session->setToken(response.firstChildElement("token").text());
				session->setUser(TXMLSerializer::unserializeUser(response.firstChildElement("user")));
				TSessionPointer pointer(session);
				emit loginFinished(false, pointer);
			}
		}
	}
	else
	{
		if (reply->error() == QNetworkReply::RemoteHostClosedError)
		{

			QNetworkAccessManager *manager = (QNetworkAccessManager*)sender();
			QTime timeTmp = manager->property("timeLoginCounter").toTime();
			int elepse = timeTmp.elapsed();

			if (manager->property("connectCount").toInt() >= 1000 || elepse >= 10000)
			{
				emit loginFinished(true, TSessionPointer(NULL));
				return;
			}
			innerLogin(manager);
			return;
		}
		TContext::instance()->logger()->error("logon error code:" + QString::number(reply->error()));
		TContext::instance()->logger()->error("logon error message:" + reply->errorString());
		emit loginFinished(true, TSessionPointer(NULL));
	}
}

void TAuthenticator::modifyDone(QNetworkReply *reply)
{
	QDomElement response;
	if(reply->error()==QNetworkReply::NoError)
	{
		QByteArray responseBody = reply->readAll();
		QString errorMessage;
		int errorLine;
		int errorColumn;
		QDomDocument doc;
		if(!doc.setContent(responseBody, &errorMessage, &errorLine, &errorColumn))
		{
			TContext::instance()->logger()->error("Parse the requester response failed: " + responseBody);
			emit modifyPasswordFinished(true);
		}
		else
		{
			response = doc.documentElement();
			QDomElement errorElement = response.firstChildElement("error");
			if(!errorElement.isNull())
			{
				TContext::instance()->logger()->error("Backbone request error: " + errorElement.attribute("code"));
				emit modifyPasswordFinished(true);
			}
			else
			{
				emit modifyPasswordFinished(false);
			}
		}
	}
	else
	{
		TContext::instance()->logger()->error("modifyPassword error code:" + QString::number(reply->error()));
		TContext::instance()->logger()->error("modifyPassword error message:" + reply->errorString());
		emit modifyPasswordFinished(true);
	}
}
